package com.zxl.placeholderParse;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class CustomTagParse {
    
    /**
     * EL表达式的正则匹配${abc}
     */
    private final String elRegex = "\\$\\{([\\p{Blank}\\w]+)\\}";
    
    /**
     * for循环的开始结束标签匹配<foreach...</foreach
     */
    private final String forRegex = "<(\\/)?foreach";
    
    /**
     * 标签属性正则校验
     */
    private final String tagAttrRegex = "([a-zA-Z]+)\\=\"(\\p{Blank}*[\\w]+\\p{Blank}*)\"";
    
    public String parse(InputStream is,Map<String, Object> map) throws IOException {
        //找到for循环的标志
        boolean nodeFlag = false;
        Pattern elPar = Pattern.compile(elRegex);
        Pattern forPar = Pattern.compile(forRegex);
        Matcher matcher = null;

        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        //最终结果
        StringBuffer buffer = new StringBuffer();
        //循环标签体，即在for循环标签中间的所有内容
        List<String> loopBodyList = new ArrayList<String>();
        String str = null;
        while ((str = reader.readLine()) != null) {
            matcher = forPar.matcher(str);
            while (matcher.find()) {
                //标注找到for循环，预示着接下来的都为for循环体，直接放入list，不做其它操作
                nodeFlag = true;
                //遇到循环结束标签
                if (matcher.group(1) != null && matcher.group(1).equals("/")) {
                    //处理for循环
                    doForLoop(loopBodyList,map,buffer);
                    //取消标志
                    nodeFlag = false;
                }
            }
            if (nodeFlag) { //for循环范围内的语句直接加入list
                loopBodyList.add(str.trim());
                continue;
            }else { //for循环外的需要做此判断
                matcher = elPar.matcher(str);
                while (matcher.find()) {
                    str = str.replace(matcher.group(0), String.valueOf(map.get(matcher.group(1).trim())));
                };
            }
            buffer.append(str);
        }
        return buffer.toString();
//        System.out.println(list.toString());
//        System.out.println(buffer.toString());
    }
    
    /**
     * 将for标签执行for循环
     * @param list  for循环体
     * @param map    将用来进行替换值的集合
     * @param sb    处理之后拼接的html
     * @throws SecurityException 
     * @throws NoSuchMethodException 
     */
    @SuppressWarnings("unchecked")
    public void doForLoop(List<String> loopBodyList,Map<String, Object> map, StringBuffer sb){
        //for循环的头部
        String forHead = loopBodyList.remove(0);
        Pattern elPar = Pattern.compile(elRegex);
        Pattern attrPar = Pattern.compile(tagAttrRegex);
        Matcher matcher = attrPar.matcher(forHead);
        //用来循环输出的集合对象
        Collection<Object> ol = null;
        //属性名
        String attrName = null;
        while (matcher.find()) {
//            forHead = forHead.replace(matcher.group(0), String.valueOf(map.get(matcher.group(2).trim())));
            attrName = matcher.group(1).trim();
            if (attrName.equals("collection")) {
                ol = (Collection<Object>) map.get(matcher.group(2).trim());
                ol = ol == null ? new ArrayList<Object>() : ol;
            }
        };
//        System.out.println(forHead);
        int lblSize = loopBodyList.size();
        String listItem = "";
        for (Object obj : ol) {
            //循环标签体
            for (int i = 0; i < lblSize; i++) {
//                System.out.println(loopBodyList.get(i));
                listItem = loopBodyList.get(i);
                matcher = elPar.matcher(listItem);
                while (matcher.find()) {
//                    forHead = forHead.replace(matcher.group(0), String.valueOf(map.get(matcher.group(1).trim())));
                    listItem = listItem.replace(matcher.group(0), InvokeGetMethod(obj, matcher.group(1).trim()).toString());
                };
                sb.append(listItem);
            }
        }
    }
    
    /**
     * 执行get
     * @return
     */
    private Object InvokeGetMethod(Object obj, String attrName){
        char firstChar = attrName.charAt(0);
        if (firstChar >= 97 && firstChar <= 122) {
            attrName = attrName.replaceFirst(firstChar + "", Character.toUpperCase(firstChar) + "");
        }
        try {
            Method method = obj.getClass().getMethod("get" + attrName);
            return method.invoke(obj);
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }
        return "";
    }
    
}
